package com.evola.conditionalformatting
{
	import mx.collections.ICollectionView;
	import mx.utils.ObjectUtil;
	import mx.utils.StringUtil;

	public class ViewFunction
	{

		//cist regex = !=|_=|>=|<=|!\^|\[\]|\.\||\|\.|!_|<>|><|>\||<\||=|>|<|\^|_
		public static const REGEX:RegExp=new RegExp("!=\|_=\|>=\|<=\|!\\\^\|\\\[\\\]\|\\\.\\\|\|\\\|\\\.\|!_\|<>\|><\|>\\\|\|<\\\|\|=\|>\|<\|\\\^\|_", "g");

		public static const NOT_EQUALS:String="!=";
		public static const BLANK_EQUALS:String="_=";
		public static const GREATER_EQUALS:String=">=";
		public static const LESS_EQUALS:String="<=";
		public static const NOT_CONTAINS:String="!^";
		public static const IN:String="[]";
		public static const STARTS:String=".|";
		public static const ENDS:String="|.";
		public static const NOT_BLANK:String="!_";
		public static const BETWEEN:String="<>";
		public static const NOT_BETWEEN:String="><";
		public static const ABOVE_AVERAGE:String=">|";
		public static const BELOW_AVERAGE:String="<|";
		public static const EQUALS:String="=";
		public static const GREATER:String=">";
		public static const LESS:String="<";
		public static const CONTAINS:String="^";
		public static const BLANK:String="_";

		public var value:String;

		public function ViewFunction(value:String)
		{

			this.value=value;
		}

		/**
		 * Funkcija racuna da li objekat ispunjava uslov definisan operatorom.
		 * @param leftValue - vrednost levog operanda
		 * @param rightValue - vrednost desnog operanda
		 * @param dataProvider - kolekcija kojoj objekat pripada, koristi se kod agregacionih funkcija, inace moze biti null
		 * @return - true ako objekat ispunjava uslov odnosno false ako ne ispunjava
		 *
		 */
		public function execute(leftValue:*, rightValue:*, dataProvider:ICollectionView, leftViewValue:ViewValue, rightViewValue:ViewValue):Boolean
		{

			var result:Boolean;

			switch (value)
			{

				case NOT_EQUALS:
				{

					result=ObjectUtil.compare(leftValue, rightValue) != 0;
					break;
				}

				case BLANK_EQUALS:
				{
					result=leftValue == null || rightValue == null || isNaN(leftValue) || isNaN(rightValue) || ObjectUtil.compare(leftValue, rightValue) == 0;
					break;
				}

				case GREATER_EQUALS:
				{
					if (isNaN(leftValue as Number) || isNaN(rightValue as Number))
						result=false;
					else
						result=ObjectUtil.compare(leftValue, rightValue) >= 0;
					break;
				}

				case LESS_EQUALS:
				{
					if (isNaN(leftValue as Number) || isNaN(rightValue as Number))
						result=false;
					else
						result=ObjectUtil.compare(leftValue, rightValue) <= 0;
					break;
				}

				case NOT_CONTAINS:
				{

					var contains : Boolean = result=leftValue && rightValue ? String(leftValue).indexOf(String(rightValue)) != -1 : false;
					result = !contains;
					break;
				}

				case IN:
				{

					//TODO
					break;
				}

				case STARTS:
				{

					result=leftValue && rightValue ? String(leftValue).indexOf(String(rightValue)) == 0 : false;
					break;
				}

				case ENDS:
				{

					var strl:String=String(leftValue);
					var strr:String=String(rightValue);
					result=leftValue && rightValue ? strl.substr(strl.length - strr.length) == strr : false;
					break;
				}

				case NOT_BLANK:
				{

					result=leftValue != null && !isNaN(leftValue as Number);
					break;
				}

				case BETWEEN:
				{

					//TODO
					break;
				}

				case NOT_BETWEEN:
				{

					//TODO
					break;
				}

				case ABOVE_AVERAGE:
				{

					//avg operatori rade tako sto pokusavaju iz dataprovidera da izracunaju 
					//srednju vrednost a na osnovu naziva polja sa leve strane posto je AVG
					//operator unarni
					result=Number(leftValue) > getAverage(dataProvider, leftViewValue);
					break;
				}

				case BELOW_AVERAGE:
				{

					result=Number(leftValue) < getAverage(dataProvider, leftViewValue);
					break;
				}

				case EQUALS:
				{
					result=ObjectUtil.compare(leftValue, rightValue) == 0;
					break;
				}

				case GREATER:
				{
					if (isNaN(leftValue as Number) || isNaN(rightValue as Number))
						result=false;
					else
						result=ObjectUtil.compare(leftValue, rightValue) > 0;
					break;
				}

				case LESS:
				{

					//NaN ne koristimo za poredjenje
					if (isNaN(leftValue as Number) || isNaN(rightValue as Number))
						result=false;
					else
						result=ObjectUtil.compare(leftValue, rightValue) < 0;
					break;
				}

				case CONTAINS:
				{

					result=leftValue && rightValue ? String(leftValue).indexOf(String(rightValue)) != -1 : false;
					break;
				}

				case BLANK:
				{

					result=leftValue == null || isNaN(leftValue as Number);
					break;
				}

				default:
				{

					result=true;
					break;
				}
			}

			return result;
		}

		public function toExpressionString():String
		{

			return value;
		}

		private function getAverage(dataProvider:ICollectionView, viewValue:ViewValue):Number
		{

			if (viewValue.type != ViewValue.TYPE_VARIABLE)
				throw new Error("When calculating average, left hand value must be a variable.");

			var total:Number=0;

			for each (var item:Object in dataProvider)
			{

				var value:Number=Number(item[viewValue.value]);
				total+=value;
			}

			var avg:Number=total / dataProvider.length;

			return avg;
		}

	}
}
